import processing.opengl.*;
import ddf.minim.signals.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import processing.serial.*;
import arduino.*;
import controlP5.*;

Minim minim;
AudioInput in;
AudioPlayer song;
FFT fft;
PFont font;

int redPin = 3;
int greenPin = 6;
int bluePin = 5;
int sliders = 1;
int smoothedRed = 0;
int smoothedBlue = 0;
int smoothedGreen = 0;
boolean beat, mp3;
int smoother = 1;
float amp;
float[] leds;
int count, count2, anim, window, wave, k;
int RED, GREEN, BLUE;
int beattime;
int pbeattime;
//Arduino arduino; // Setup an arduino object to communicate with Firmata firmware
BeatDetect beat2;
Serial arduino; //creates object "port" of serial class


void setup()
{
size(700, 510, OPENGL);
colorMode(RGB);
background(0);
//arduino = new Arduino(this, Arduino.list()[1], 9600);
  arduino = new Serial(this, Serial.list()[1],9600); //set baud rate

mp3 = false;
minim = new Minim(this);
beat2 = new BeatDetect();
if(mp3) {
song = minim.loadFile("11 Wild Horses [Feat. Adam Levine].mp3", 128);
beat2.detect(song.mix);
song.play();
fft = new FFT(song.bufferSize(), song.sampleRate()); }
else{
in = minim.getLineIn(Minim.STEREO, 1024);
beat2.detect(in.mix);
fft = new FFT(in.bufferSize(), in.sampleRate()); 
}
beat2.setSensitivity(300);
fft.logAverages(100, 4);
rectMode(CORNERS);
count = count2 = 0;
anim = 1;
beat = false;
window = 1;
k = 0;
beattime = pbeattime = 0;
}

void draw() {
if(mp3) beat2.detect(song.mix);
else beat2.detect(in.mix);
fill(0, 255);
rect (0, 0, width, height);
float[] leds = new float[fft.avgSize()];
if(beat) fill(0, 200, 200, 50);
rect(0, 0, width, height);
fill(150);
if(mp3) fft.forward(song.mix);
else fft.forward(in.mix);
int w = int(width/fft.avgSize());
for(int i = 0; i < fft.avgSize() && sliders == 1; i++)
{
float fftout = fft.getAvg(i); 
amp = constrain(fftout*exp(fftout*.01)*exp(i/8)*.5, 0, 255);
if(window == 1){
fill(0, 200, 0, 50 + amp);
rect(i*w, height/2, i*w + w, height/2 - amp); //this draws the scaled spectrum
rect(i*w, height/2, i*w + w, height/2 + amp);
fill(0, 200, 100, 50 + amp);
rect(i*w, height/2, i*w + w, height/2 - fftout*2); //this draws raw spectrum on top
rect(i*w, height/2, i*w + w, height/2 + fftout*2);
leds[i] = amp;
}
}

if(sliders == 1){
if(leds[0] + leds[1] + leds[2] > 730) //this checks two bass bands and considers peaks to be a beat
beat = true;
else beat = false;
if(anim == 1) anim1(leds);
if(anim == 2) anim2(leds);
if(anim == 3) anim3(leds);
if(anim == 4) anim4(leds);
if(anim == 5) anim5(leds);
if(anim == 6) anim6(leds);
if(anim == 7) anim7(leds);
if(anim == 8) anim8(leds);
if(anim == 9) anim9(leds);
if(anim == 10) anim10(leds);
if(anim == 11) anim11(leds);
if(anim == 12) anim11(leds);
if(anim == 13) anim11(leds);
if(anim == 14) anim11(leds);
}

if(sliders == 2) drawSliders();
if(smoother == 1){
smoothVals();
RED = smoothedRed;
GREEN = smoothedGreen;
BLUE = smoothedBlue;
}
//arduino.analogWrite(redPin, RED);
//arduino.analogWrite(greenPin, GREEN);
//arduino.analogWrite(bluePin, BLUE);
//println(RED+","+GREEN+","+BLUE+"\n"); //put any variable you want to monitor here
arduino.write(RED+","+GREEN+","+BLUE+"\n"); //write blue value
delay(1);
count++; //counts number of cycles since this anim started

println(+ count + " " + anim); //put any variable you want to monitor here
if(count > 200 && beat) { //this makes sure a certain amount of time passes
anim = int(random(1, 14)); //before changing anims
count = 0;
count2 = 0;
}

if(beat) {
count2 = 0;
pbeattime = beattime;
}

if(!beat){ //this times how long its been since a beat. after a certain point,
count2++; // Counts how long since a beat
if(count2 > 200){
anim = 1; //revert to anim1 if no beats for a while
count2 = 0;
}
}
}

void smoothVals(){
float filterVal = 0.5;

if (filterVal > 1){ // check to make sure param's are within range
filterVal = .99;
}
else if (filterVal <= 0){
filterVal = 0;
}

smoothedRed = int((RED * (1 - filterVal)) + (smoothedRed * filterVal));
smoothedGreen = int((GREEN * (1 - filterVal)) + (smoothedGreen * filterVal));
smoothedBlue = int((BLUE * (1 - filterVal)) + (smoothedBlue * filterVal));

}

void keyReleased(){ 
if(key == '1') //this forces a specific animation
anim += 1;
if(key == 's'){
if(sliders == 1) sliders = 2; //this toggles SA or LED sim
else sliders = 1;
} 
if(key == 'f') //this forces a specific animation
smoother *= -1;
}

void drawSliders(){
RED = 255;
GREEN = 255;
BLUE = 122;
background(RED, GREEN, BLUE);
}






/*ANIMATIONS*/



void anim1(float leds[]) {
k++;
float angle = 0.001*k;
float sinmap = map(sin(angle), -1, 1, 0, fft.avgSize() - 1); //this creates a periodic fft band shifter
float cosmap = map(cos(angle*2), -1, 1, 0, fft.avgSize() - 1); 
float sinmap2 = map(cos(2 + angle*3), -1, 1, 0, fft.avgSize() - 1); 
RED = int(leds[int(sinmap)]);
GREEN = int(leds[int(cosmap)]);
BLUE = int(leds[int(sinmap2)]);
if(beat) getColor(); //getColor pulses a random color on every detected beat
}

void anim2(float leds[]) {
RED = 0;
GREEN = 0;
BLUE = int(leds[2]);
if(beat) {
int pRED = RED; //pRED is a placeholder variable for previous RED array location
RED = GREEN;
int pGREEN = GREEN;
GREEN = BLUE;
int pBLUE = BLUE;
BLUE = RED;
}
}

void anim3(float leds[]) {
RED = int(leds[2]);
GREEN = 0;
BLUE = 0;
if(beat) { 
BLUE = RED; 
GREEN = RED;
RED = GREEN;
}
}


void anim4(float leds[]) {
RED = int(leds[15]);
GREEN = 0;
BLUE = int(leds[6]);
if(beat) { 
BLUE = int(leds[2]); 
GREEN = int(leds[2]);
RED = int(leds[2]);
}
}

void anim5(float leds[]) {
k++;
float angle = 0.08*k;
float sinmap = map(sin(angle), -1, 1, 0, fft.avgSize() - 1); //this creates a periodic fft band shifter
float cosmap = map(cos(angle*2), -1, 1, 0, fft.avgSize() - 1); 
float sinmap2 = map(cos(2 + angle*3), -1, 1, 0, fft.avgSize() - 1); 
RED = int(leds[int(sinmap)]);
GREEN = int(leds[int(cosmap)]);
BLUE = int(leds[int(sinmap2)]);
if(beat) { 
BLUE = int(leds[2]); 
GREEN = int(leds[2]);
RED = 0;
}
}

void anim6(float leds[]) {
RED = 0;
GREEN = int(leds[15]);
BLUE = 0;
if(beat) { 
getColor();
}
}

void anim7(float leds[]) {
RED = int(leds[15]);
GREEN = int(leds[15]*.25);
BLUE = 0;
if(beat){
BLUE = 255;
}
}

void anim8(float leds[]) {
RED = int(leds[15]*.8);
GREEN = 0;
BLUE = int(leds[15]*.25);
if(beat){
BLUE = 255;
RED = 255;
}
}

void anim9(float leds[]) {
RED = int(leds[15]*.8);
GREEN = 0;
BLUE = int(leds[15]*.25);
if(beat){
BLUE = 255;
RED = 255;
}
}

void anim10(float leds[]) {
RED = 0;
GREEN = 10;
BLUE = 10;
if(beat){
BLUE = 255;
GREEN = 255;
}
}

void anim11(float leds[]) {
RED = 0;
GREEN = int(leds[15]);
BLUE = int(leds[0]*2);
if(beat){
BLUE = 255;
RED = 255;
}
}

void anim12(float leds[]) {
RED = 10;
GREEN = 10;
BLUE = 10;
if(beat){
RED = 255;
BLUE = 255;
GREEN = 255;
}
}

void anim13(float leds[]) {
RED = 0;
GREEN = 0;
BLUE = 10;
if(beat){
RED = 0;
BLUE = 255;
GREEN = 0;
}
}

void anim14(float leds[]) {
RED = 10;
GREEN = 30;
BLUE = 10;
if(beat){
RED = 200;
BLUE = 255;
GREEN = 100;
}
}

void getColor() {
int temp = int(random(0, 7));
if(temp == 1) {
BLUE = 255; 
GREEN = 0;
RED = 0;
}
if(temp == 2) {
BLUE = 0;
GREEN = 255;
RED = 0;
}
if(temp == 3) {
BLUE = 0;
GREEN = 0;
RED = 0;
}
if(temp == 4) {
BLUE = 255;
GREEN = 0;
RED = 255;
}
if(temp == 5) {
BLUE = 0;
GREEN = 255;
RED = 255;
}
if(temp == 6) {
BLUE = 150;
GREEN = 150;
RED = 255;
}
}
